package com.snapp.web;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.output.XMLOutputter;
import org.puresilk.afx.base.SilkAfxAction;

import com.oreilly.servlet.MultipartRequest;

public class SNAppAction extends SilkAfxAction {
	
	// dbo global identifier
	private String snappGlobalId = null;
	
	// result codes
	public static int RESULT_CODE_SUCCESS = 1;
	public static int RESULT_CODE_WARNING = 0;
	public static int RESULT_CODE_ERROR = -1;
	
	private int resultCode = 0;
	private String resultMessage = "No message set.";
	private Element bodyElement = null;
	
	public String execute(HttpServletRequest req) {
		return snappResponse(req);
	}
	
	public String snappResponse(HttpServletRequest req) {
		req.setAttribute("document", buildResponseDoc());

		HttpServletResponse response = getResponse(req);

		// test
		response.setHeader("Access-Control-Allow-Origin", "*");
		
		//set response for XML mime type
		response.setContentType("text/xml");

		// retrieve xml dom
		Document doc = (Document) req.getAttribute("document");

		// prepare outputter
		XMLOutputter xo = new XMLOutputter();

		// print put xml
		String output = xo.outputString(doc.getRootElement());

		PrintWriter pw = null;
		try {
			pw = response.getWriter();
			pw.write(output);
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			pw.flush();
			pw.close();
		}
		
		return NO_JSP_DISPATCH;
	}
	
	/**
	 * Return a single file to response..
	 * 
	 * @param req
	 * @param file
	 * @return
	 */
	protected String fileResponse(HttpServletRequest req, File file) {
		// intercept the response
		HttpServletResponse response = getResponse(req);
		response.setHeader("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"");
		
		// set up reader and writer
		FileInputStream fr = null;
		OutputStream wr = null;
		try {
			// reader
			fr = new FileInputStream(file);
			
			// writer
			wr = response.getOutputStream();
			// use 1KB buffer
			byte[] buf = new byte[1024];
			int r = 0;
			// read each KB
			while ((r = fr.read(buf)) > -1) {
				// write the KB
				wr.write(buf,0,r);	
			}
			// clean up 
			wr.flush();
			wr.close();
			fr.close();
			wr = null;
			fr = null;
			
		} catch(Exception ex) {
			log("Error writing to servlet response!!!!",ex);
		} 
		// Make damn sure we cleaned up!!
		try {
			if (fr != null) {
				fr.close();
				fr = null;
			}
			if (wr != null) {
				wr.flush();
				wr.close();
				wr = null;
			}
		} catch(Exception e) {
			// log it.
			logFatalMsg("Cannot close file streams!!!");
		}
		
		return NO_JSP_DISPATCH;

	}

	@Override
	public String execute(HttpServletRequest arg0, HttpServletResponse arg1) {
		// TODO Auto-generated method stub
		return null;
	}
	
	/**
	 * Intercepts the response from the request object
	 * @param req
	 * @return
	 */
	protected HttpServletResponse getResponse(HttpServletRequest req) {
		return (HttpServletResponse)req.getAttribute("HTTPResponse");
	}
	

	// build the document to required format..
	public Document buildResponseDoc() {
		Document doc = new Document();
		// wrapper
		Element root = new Element("snapp_response");
		// results node
		Element results = new Element("results");
		results.setAttribute("code",Integer.toString(resultCode));
		results.setAttribute("message",resultMessage);
		root.addContent(results);
		// body node
		Element body = new Element("body");
		if (bodyElement != null) {
			body.addContent(bodyElement.detach());
		}
		root.addContent(body);
		// set root
		doc.setRootElement(root);
		return doc;
	}
	
	@SuppressWarnings("unchecked")
	protected HashMap<String,String> consolidateReadMap(HttpServletRequest req) {
		return (HashMap<String,String>) consolidateMap(req);
	}

	@SuppressWarnings("unchecked")
	protected HashMap<String,Object> consolidateWriteMap(HttpServletRequest req) {
		return (HashMap<String,Object>) consolidateMap(req);
	}

	/*
	 * Convert parameter values from request to string values
	 */
	@SuppressWarnings("unchecked")
	private HashMap<String,? extends Object> consolidateMap(HttpServletRequest req) {
		HashMap<String, Object> rv = new HashMap<String, Object>();
		@SuppressWarnings("rawtypes")
		Map pmap = req.getParameterMap();
		Iterator<String> itr = pmap.keySet().iterator();
		while (itr.hasNext()) {
			String nxt = itr.next();
			// exclude action parameter and dbo global identifier
			if (!nxt.equals("action") && !nxt.equals("SNAppGlobalId")) {
				String key = nxt;
				if (nxt.indexOf("_values") > -1) {
					key = nxt.substring(0, nxt.indexOf("_values"));
					logInfoMsg("Setting "+nxt+ " to "+key);
				}
				try {
					String[] parr = ((String[])pmap.get(nxt)); 
					if (parr.length > 1) {
						String ts = "";
						for (int i = 0; i < parr.length; i++) {
							if (i > 0) ts += ",";
							ts += parr[i];
						}
						rv.put(key, ts);
					} else {
						rv.put(key, parr[0]);
					}
				} catch(Exception e) {
					rv.put(key, (String)pmap.get(nxt));
				}
			}
		}
		return rv;
	}
	
	@SuppressWarnings("unchecked")
	protected HashMap<String,String> consolidateReadMap(MultipartRequest req) {
		return (HashMap<String,String>) consolidateMap(req);
	}

	@SuppressWarnings("unchecked")
	protected HashMap<String,Object> consolidateWriteMap(MultipartRequest req) {
		return (HashMap<String,Object>) consolidateMap(req);
	}
	/*
	 * Convert parameter values from request to string values
	 */
	private Map<String,? extends Object> consolidateMap(MultipartRequest req) {
		HashMap<String, Object> rv = new HashMap<String, Object>();
		@SuppressWarnings("unchecked")
		Enumeration<String> e = req.getParameterNames();
		while(e.hasMoreElements()) {
			String nxt = e.nextElement();
			if (!nxt.equals("action") && !nxt.equals("SNAppGlobalId")) {
				String key = nxt;
				if (nxt.indexOf("_values") > -1) {
					key = nxt.substring(0, nxt.indexOf("_values"));
					logInfoMsg("Setting "+nxt+ " to "+key);
				}
				String[] parr = ((String[])req.getParameterValues(nxt)); 
				if (parr.length > 1) {
					String ts = "";
					for (int i = 0; i < parr.length; i++) {
						if (i > 0) ts += ",";
						ts += parr[i];
					}
					rv.put(key, ts);
				} else {
					rv.put(key, parr[0]);
				}
			
			}
		}
		// add the files
		@SuppressWarnings("unchecked")
		Enumeration<String> fe = req.getFileNames();
		while(fe.hasMoreElements()) {
			String fname = fe.nextElement();
			rv.put(fname, req.getFile(fname));
		}
			
		return rv;
	}

	public void setSNAppGlobalId(String dboGlobalId) {
		this.snappGlobalId = dboGlobalId;
	}

	public String getSNAppGlobalId() {
		return snappGlobalId;
	}

	public int getResultCode() {
		return resultCode;
	}
	public void setResultCode(int resultCode) {
		this.resultCode = resultCode;
	}
	public String getResultMessage() {
		return resultMessage;
	}
	public void setResultMessage(String resultMessage) {
		this.resultMessage = resultMessage;
	}
	public Element getBodyElement() {
		return bodyElement;
	}
	public void setBodyElement(Element bodyElement) {
		this.bodyElement = bodyElement;
	}

	public void setResults(int code, String msg) {
		this.resultCode = code;
		this.resultMessage = msg;
	}
}
